{
 "cells": [
  {
   "metadata": {
    "collapsed": true
   },
   "cell_type": "markdown",
   "source": [
    "# 2.5 自动微分\n",
    "\n",
    "深度学习框架通过自动计算导数，即自动微分（automatic differentiation）来加快求导。"
   ],
   "id": "43d7ee0d0cd23ecb"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:44:48.863353Z",
     "start_time": "2025-11-16T14:44:48.426530Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import torch\n",
    "\n",
    "# 创建一个行向量\n",
    "x = torch.arange(4.0)\n",
    "x"
   ],
   "id": "b80b621c4fa892ba",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0., 1., 2., 3.])"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 1
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:45:47.067868Z",
     "start_time": "2025-11-16T14:45:47.060877Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 自动求导\n",
    "x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)\n",
    "x.grad  # 默认值是None"
   ],
   "id": "e1f8524c84e0bf57",
   "outputs": [],
   "execution_count": 2
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:47:30.956288Z",
     "start_time": "2025-11-16T14:47:30.931911Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# x的点积是x1^2 + x2^2 + x3^2 + x4^4，因此函数y有四个自变量，分别对这四个自变量求偏导，再将各自的值带入，再将计算结果组成列向量，即可求出梯度\n",
    "y = 2 * torch.dot(x, x)\n",
    "y"
   ],
   "id": "66deb4fe0ae3dc7b",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(28., grad_fn=<MulBackward0>)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 3
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:48:15.051890Z",
     "start_time": "2025-11-16T14:48:15.028192Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 计算梯度\n",
    "y.backward()\n",
    "x.grad"
   ],
   "id": "7b78a6a6124d510f",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([ 0.,  4.,  8., 12.])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 4
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:53:18.927232Z",
     "start_time": "2025-11-16T14:53:18.921184Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 检验自动计算的梯度是否和通过数学求偏导得到的相同\n",
    "x.grad == 4 * x"
   ],
   "id": "cda6b6a557076ee0",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([True, True, True, True])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 5
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:55:33.030122Z",
     "start_time": "2025-11-16T14:55:33.014357Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 在默认情况下，PyTorch会累积梯度，我们需要清除之前的值\n",
    "x.grad.zero_()\n",
    "# 函数 y = x1 + x2 + x3 + x4\n",
    "y = x.sum()\n",
    "# 计算梯度\n",
    "y.backward()\n",
    "x.grad"
   ],
   "id": "346ae4df30d1020e",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1., 1., 1., 1.])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 7
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:56:30.375184Z",
     "start_time": "2025-11-16T14:56:30.367181Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 对非标量调用backward需要传入一个gradient参数，该参数指定微分函数关于self的梯度。\n",
    "# 本例只想求偏导数的和，所以传递一个1的梯度是合适的\n",
    "x.grad.zero_()\n",
    "# 函数 y = x^2\n",
    "y = x * x\n",
    "# 等价于y.backward(torch.ones(len(x)))\n",
    "# 计算梯度\n",
    "y.sum().backward()\n",
    "x.grad"
   ],
   "id": "2b151c4526c28f93",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0., 2., 4., 6.])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 8
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:58:37.950771Z",
     "start_time": "2025-11-16T14:58:37.937703Z"
    }
   },
   "cell_type": "code",
   "source": [
    "x.grad.zero_()\n",
    "y = x * x\n",
    "u = y.detach()\n",
    "z = u * x\n",
    "\n",
    "z.sum().backward()\n",
    "x.grad == u"
   ],
   "id": "844453484cf1398d",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([True, True, True, True])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 9
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:58:53.144952Z",
     "start_time": "2025-11-16T14:58:53.126736Z"
    }
   },
   "cell_type": "code",
   "source": [
    "x.grad.zero_()\n",
    "y.sum().backward()\n",
    "x.grad == 2 * x"
   ],
   "id": "d65ef94728157bfc",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([True, True, True, True])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 10
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:59:11.869815Z",
     "start_time": "2025-11-16T14:59:11.862541Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def f(a):\n",
    "    b = a * 2\n",
    "    while b.norm() < 1000:\n",
    "        b = b * 2\n",
    "    if b.sum() > 0:\n",
    "        c = b\n",
    "    else:\n",
    "        c = 100 * b\n",
    "    return c"
   ],
   "id": "a8fb008f3d486f90",
   "outputs": [],
   "execution_count": 11
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T14:59:51.415735Z",
     "start_time": "2025-11-16T14:59:51.390627Z"
    }
   },
   "cell_type": "code",
   "source": [
    "a = torch.randn(size=(), requires_grad=True)\n",
    "d = f(a)\n",
    "d.backward()"
   ],
   "id": "108dcbcc481afe78",
   "outputs": [],
   "execution_count": 12
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-11-16T15:00:06.554098Z",
     "start_time": "2025-11-16T15:00:06.538951Z"
    }
   },
   "cell_type": "code",
   "source": "a.grad == d / a",
   "id": "d23433b1cea2969b",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(True)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 13
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
